/*
* Dragger v3.0 - 03.09.12
* Copyright 2011 group94 - http://www.group94.com
* Unauthorised use, copying and/or redistributing is strictly prohibited.
*
* USAGE:
	var dragger = new Dragger($("#elem"), {cookieName:"test", moveElement:true, detectSwipe:true, minX:0, minY:0, maxX:500, maxY:200})
	
	ARGUMENTS:
	----------
	moveElement			If true: move the actual element within given restrictions (min,max). Default false.
	detectSwipe			If true: detects on mobile if you scroll or swipe an element. preventDefault is only set when you are swiping.
							Also enables onSwipe and onScroll events.
	
	EVENTS:
	-------
	dragger.onStartDrag = function(){}
	dragger.onStopDrag = function(){}
	dragger.onMouseMove = function($x, $y){}
	dragger.onSwipe = function($x, $y){}
	dragger.onScroll = function($x, $y){}
	
	METHODS:
	--------
	dragger.updateConfig({minX:20, maxX:100})		// eg. in priceSlider
	dragger.setPosition({x:0.5})						// eg. when using scrollwheel with a draggable content div
*/

function Dragger($elem, $config){
	if(!$elem)	return;
	
	var ths = this;
	ths.elem = $elem;
	if($config)	ths.config = $config;
	else			ths.config = {};
	ths.lastMouseX;
	ths.lastMouseY;
	ths.currX;
	ths.currY;
	ths.scrolling = false;
	
	ths.detectSwipe = ths.config.detectSwipe;		// if true it detects swiping or scrolling on a mobile device.
	ths.margin_scroll = 8;
	ths.margin_swipe = 8;
	
	ths.moveElement = ths.config.moveElement;		// if false it disables moving the given element.
	
	// prevent iOS press&hold-selection:
	if(ths.elem.style){
		ths.elem.onselectstart = function(){ return false; };
		ths.elem.unselectable = "on";
		setCss(ths.elem, "-webkit-user-select", "none");
	}
	
	
	//----------------------------------------------- startDrag
	ths.startDrag = function($e){
		var mXY = ths.getMousePos($e);
		ths.lastMouseX = mXY.x;
		ths.lastMouseY = mXY.y;
		
		ths.startMouseX = ths.lastMouseX;
		ths.startMouseY = ths.lastMouseY;
		ths.scrolling = false;
		ths.swiping = false;
		
		if(ths.elem.style && ths.moveElement){
			ths.currX = getCss(ths.elem, "left");
			ths.currY = getCss(ths.elem, "top");
		}else{
			ths.currX = 0;
			ths.currY = 0;
		}
		
		if(!agent.mobile){
			addEvent(document, "mousemove", ths.mouseMove);
			addEvent(document, "mouseup", ths.stopDrag);
		}
		
		if(ths.onStartDrag)	ths.onStartDrag();
	}
	
	
	//----------------------------------------------- mouseMove
	ths.mouseMove = function($e){
		var mXY = ths.getMousePos($e);
				
		var posX = ths.currX + (mXY.x-ths.lastMouseX);
		var posY = ths.currY + (mXY.y-ths.lastMouseY);
		
		if(ths.config.minX != null)	posX = Math.max(posX, ths.config.minX);
		if(ths.config.maxX != null)	posX = Math.min(posX, ths.config.maxX);
		if(ths.config.minY != null)	posY = Math.min(posY, ths.config.maxY);
		if(ths.config.maxY != null)	posY = Math.max(posY, ths.config.minY);
		
		if(ths.elem.style && ths.moveElement){
			if(ths.config.minX == null || ths.config.minX !== ths.config.maxX)	setCss(ths.elem, "left", posX);
			if(ths.config.minY == null || ths.config.minY !== ths.config.maxY)	setCss(ths.elem, "top", posY);
		}
		
		if(!ths.scrolling){
			if(ths.detectSwipe && (mXY.x > (ths.startMouseX+ths.margin_swipe) || mXY.x < (ths.startMouseX-ths.margin_swipe)) )	ths.swiping = true;
			if(ths.onMouseMove)	ths.onMouseMove(posX, posY);
			
			if(ths.swiping || !ths.detectSwipe){
				if(ths.detectSwipe && ths.onSwipe)	ths.onSwipe(posX, posY);
				ths.lastMouseX = mXY.x;
				ths.lastMouseY = mXY.y;
				ths.currX = posX;
				ths.currY = posY;
				//$e.preventDefault();
				try{ ($e.preventDefault) ? $e.preventDefault() : $e.returnValue = false; }catch(evt){}
				
			}else{
				if(mXY.y > (ths.startMouseY+ths.margin_scroll) || mXY.y < (ths.startMouseY-ths.margin_scroll))	ths.scrolling = true;
			}
		}else{
			if(ths.detectSwipe && ths.onScroll)	ths.onScroll(posX, posY);
		}
	}
	
	
	//----------------------------------------------- stopDrag
	ths.stopDrag = function($e){
		//$e.preventDefault();		// disable clicking button when releasing after drag
		try{ ($e.preventDefault) ? $e.preventDefault() : $e.returnValue = false; }catch(evt){}
		
		if(!agent.mobile){
			removeEvent(document, "mousemove", ths.mouseMove);
			removeEvent(document, "mouseup", ths.stopDrag);
		}
		if(ths.elem.style && ths.moveElement && ths.config.cookieName){
			setCookie(ths.config.cookieName+"_x", getCss(ths.elem, "left"));
			setCookie(ths.config.cookieName+"_y", getCss(ths.elem, "top"));
		}
		if(ths.onStopDrag)	ths.onStopDrag(ths.currX, ths.currY);
	}
	
	
	//----------------------------------------------- update config
	ths.updateConfig = function($config){
		if($config.minX != null)	ths.config.minX = $config.minX;
		if($config.maxX != null)	ths.config.maxX = $config.maxX;
		if($config.minY != null)	ths.config.minY = $config.minY;
		if($config.maxY != null)	ths.config.maxY = $config.maxY;
	}
	
	
	//----------------------------------------------- set position
	ths.setPosition = function($pos){
		if(ths.elem.style && ths.moveElement){
			if($pos.x!=null)	setCss(ths.elem, "left", $config.minX + ($config.maxX-$config.minX)*$pos.x); 
			if($pos.y!=null)	setCss(ths.elem, "top", $config.minY + ($config.maxY-$config.minY)*$pos.y);
		} 
	}
	
	//----------------------------------------------- mouse/touch events
	ths.getMousePos = function($e){
		if(agent.mobile){
			$e = $e.touches[0];
			return {x:$e.pageX, y:$e.pageY};
		}else{
			try{ (event.preventDefault) ? event.preventDefault() : event.returnValue = false; }catch(evt){}
			if(typeof $e=="undefined") $e = window.event;
			return {x:$e.clientX, y:$e.clientY};
		}
	}

	ths.touchHandler = function($e){		// mobile events:
		if($e.type == "touchstart")											ths.startDrag($e);
		else if($e.type == "touchmove")										ths.mouseMove($e);
		else if($e.type == "touchend" || $e.type == "touchcancel")	ths.stopDrag($e);
	}
	
	//----------------------------------------------- init
	if(ths.config.cookieName && ths.elem.style && ths.moveElement){
		setCss(ths.elem, "left", getCookie(ths.config.cookieName+"_x"));
		setCss(ths.elem, "top", getCookie(ths.config.cookieName+"_y"));
	}
	
	if(agent.mobile){
		addEvent(ths.elem, "touchstart", ths.touchHandler);
		addEvent(ths.elem, "touchmove", ths.touchHandler);
		addEvent(ths.elem, "touchend", ths.touchHandler);
	}else{
		addEvent(ths.elem, "mousedown", ths.startDrag);
	}
}